/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.tools;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.AlgorithmParameters;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import com.unboundid.util.Base64;
/**
* This program can be used to generate Easter eggs for inclusion in software
* that is based on HTML pages. It works by accepting the query string that is
* to be used to access the easter egg, generating an MD5 hash of the query
* string that should be used to determine when the user has entered that query
* string in the URL (so that the clear-text query string does not appear in the
* application source), and then reading a file with the data that should be
* displayed when this egg is invoked and re-writing it to a DES-encrypted file
* with a key of the clear-text query string.
*
*
* @author Neil A. Wilson
*/
public class CreateEgg
{
/**
* The salt that will always be used for encryption. Since we don't care that
* much about security in this case, the salt can be weak for added
* convenience.
*/
public static final byte[] SALT = { 0, 0, 0, 0, 0, 0, 0, 0 };
/**
* The number of iterations to apply to the encryption algorithm.
*/
public static final int ITERATIONS = 1000;
/**
* The name of the cipher to use for the encryption.
*/
public static final String CIPHER_NAME = "PBEWithMD5AndDES";
/**
* Parses the command-line arguments and performs the appropriate processing.
*
* @param args The command-line arguments provided to this program.
*
* @throws Exception If a problem occurs while performing any processing.
*/
public static void main(String[] args)
throws Exception
{
String queryString = null;
String inputFile = null;
String outputFile = null;
boolean decrypt = false;
// Parse the command-line arguments provided to the program.
for (int i=0; i < args.length; i++)
{
if (args[i].equals("-q"))
{
queryString = args[++i];
}
else if (args[i].equals("-i"))
{
inputFile = args[++i];
}
else if (args[i].equals("-o"))
{
outputFile = args[++i];
}
else if (args[i].equals("-d"))
{
decrypt = true;
}
else if (args[i].equals("-H"))
{
displayUsage();
System.exit(0);
}
else
{
System.err.println("ERROR: Unrecognized argument\"" + args[i] + '"');
displayUsage();
System.exit(1);
}
}
// Validate the parameters provided.
if (queryString == null)
{
System.err.println("ERROR: No query string provided (use -q)");
displayUsage();
System.exit(1);
}
if (inputFile == null)
{
System.err.println("ERROR: No input file provided (use -i)");
displayUsage();
System.exit(1);
}
if (outputFile == null)
{
if (decrypt)
{
outputFile = inputFile + ".decrypted";
}
else
{
outputFile = inputFile + ".encrypted";
}
}
// Perform the appropriate encryption or decryption based on the provided
// command-line arguments.
if (decrypt)
{
// Initialize the decryption mechanism.
AlgorithmParameters algorithmParams =
AlgorithmParameters.getInstance(CIPHER_NAME);
algorithmParams.init(new PBEParameterSpec(SALT, ITERATIONS));
SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance(CIPHER_NAME);
SecretKey key =
keyFactory.generateSecret(new PBEKeySpec(queryString.toCharArray()));
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
cipher.init(Cipher.DECRYPT_MODE, key, algorithmParams);
// Open the files and do the decryption.
int bytesIn;
int bytesOut;
int totalBytesRead = 0;
int totalBytesWritten = 0;
byte[] inBuffer = new byte[4096];
byte[] outBuffer = new byte[8192];
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(outputFile);
while ((bytesIn = inputStream.read(inBuffer)) > 0)
{
bytesOut = cipher.update(inBuffer, 0, bytesIn, outBuffer);
outputStream.write(outBuffer, 0, bytesOut);
totalBytesRead += bytesIn;
totalBytesWritten += bytesOut;
}
outputStream.write(cipher.doFinal());
inputStream.close();
outputStream.flush();
outputStream.close();
System.out.println("Read " + totalBytesRead + " bytes from " + inputFile);
System.out.println("Wrote " + totalBytesWritten + " bytes to " +
outputFile);
}
else
{
// Create an MD5 hash of the query string.
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
byte[] queryHashBytes = md5Digest.digest(queryString.getBytes("UTF-8"));
String queryHashStr = Base64.encode(queryHashBytes);
System.out.println("MD5 hash of query string is " + queryHashStr);
// Initialize the encryption mechanism.
AlgorithmParameters algorithmParams =
AlgorithmParameters.getInstance(CIPHER_NAME);
algorithmParams.init(new PBEParameterSpec(SALT, ITERATIONS));
SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance(CIPHER_NAME);
SecretKey key =
keyFactory.generateSecret(new PBEKeySpec(queryString.toCharArray()));
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, key, algorithmParams);
// Open the files and do the encryption.
int bytesIn;
int bytesOut;
int totalBytesRead = 0;
int totalBytesWritten = 0;
byte[] inBuffer = new byte[4096];
byte[] outBuffer = new byte[8192];
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(outputFile);
while ((bytesIn = inputStream.read(inBuffer)) > 0)
{
bytesOut = cipher.update(inBuffer, 0, bytesIn, outBuffer);
outputStream.write(outBuffer, 0, bytesOut);
totalBytesRead += bytesIn;
totalBytesWritten += bytesOut;
}
outputStream.write(cipher.doFinal());
inputStream.close();
outputStream.flush();
outputStream.close();
System.out.println("Read " + totalBytesRead + " bytes from " + inputFile);
System.out.println("Wrote " + totalBytesWritten + " bytes to " +
outputFile);
}
}
/**
* Displays usage information for this program.
*/
public static void displayUsage()
{
System.out.println("USAGE: java CreateEgg -q {queryString} " +
"-i {inputFile} -o {outputFile} [-d]");
}
}